package com.ctvit.framework.dao.ibatis;

import java.beans.PropertyDescriptor;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.springframework.orm.ibatis.SqlMapClientCallback;

import com.ctvit.framework.dao.Condition;
import com.ctvit.framework.dao.GenericDao;
import com.ctvit.framework.dao.OrderPart;
import com.ctvit.framework.domain.BaseBean;
import com.ibatis.sqlmap.client.SqlMapExecutor;
import com.ibatis.sqlmap.client.event.RowHandler;
import com.ibatis.sqlmap.engine.mapping.statement.RowHandlerCallback;
import com.mysql.jdbc.ResultSet;

/**
 *
 *
 * @author Q-Wang
 */
@SuppressWarnings({"unchecked","unused","rawtypes"})
public final class GenericDaoIbatis extends BaseDao implements GenericDao {
	private static final String POSTFIX_INSERT = ".insert";

	private static final String POSTFIX_INSERT_BY_MAP = ".insertByMap";

	private static final String POSTFIX_UPDATE = ".update";

	private static final String POSTFIX_UPDATE_Sample = ".updateBySample";

	private static final String POSTFIX_DELETE_ID = ".deleteById";

	private static final String POSTFIX_DELETE_SAMPLE = ".deleteBySample";

	private static final String POSTFIX_SELECT_ID = ".selectById";

	private static final String POSTFIX_SELECT_SAMPLE = ".selectBySample";

	private static final String POSTFIX_SELECT_PAGE_SAMPLE = ".selectPageBySample";

	private static final String POSTFIX_COUNT = ".count";

	/**
	 * @see com.dota.framework.dao.ibatis.GenericDAO#executeSql(java.lang.String)
	 */
	@Override
	public List executeSql(String sql) {
		return getSqlMapClientTemplate().queryForList(
				FRAMEWORK_DAO_NAMESPACE + ".query", sql);

	}
	public List executeSqlRowHandler(String sql) {
		final List mapList=new ArrayList();
		getSqlMapClientTemplate().queryWithRowHandler(FRAMEWORK_DAO_NAMESPACE + ".query",sql, new RowHandler() {
			@Override
			public void handleRow(Object arg0){
		    Map map=(Map)arg0;
		    HashMap<String, String> hMap=new HashMap<String, String>();
		    for (Object key:map.keySet()) {
		    	hMap.put(String.valueOf(key), String.valueOf(map.get(key)));
		    }
//			ResultSet rs=(ResultSet)arg0;
//			HashMap<String, String> map=new HashMap<String, String>();
//			try {
//				ResultSetMetaData rsm   =rs.getMetaData();
//				int col =   rsm.getColumnCount();   //获得列的个数
//			    String   colName[] = new String[col];
//			    for (int i = 0; i < col; i++)   {  
//			        colName[i]   = rsm.getColumnName( i + 1 ); 
//			        map.put(colName[i], rs.getString(colName[i]));
//			     }
//			} catch (Exception e) {
//				e.printStackTrace();
//			}
		    mapList.add(hMap);
			}
		});
		return mapList;
	}
	/**
	 * @see com.dota.framework.dao.ibatis.GenericDAO#queryBySql(java.lang.String, java.lang.Object)
	 */
	@Override
	public List queryBySqlID(String sqlid, Object parameter) {
		return getSqlMapClientTemplate().queryForList(
				sqlid, parameter);
	}
	@Override
	public List queryBySqlIDPage(String sqlid, Object parameter,int pageNo, int pageSize) {
		int offset = pageNo * pageSize;
		Map map=(Map)parameter;
		map.put("pageinfo", new PageBean(offset, pageSize));
		return getSqlMapClientTemplate().queryForList(
				sqlid, parameter);
	}
	@Override
	public long queryBySqlIDPageCount(String sqlid, Object parameter) {
		Long count = (Long) getSqlMapClientTemplate().queryForObject(sqlid,parameter);
		if (count != null) {
			return count.longValue();
		}
		return 0;
	}
	/**
	 * ִ��update���͵�sql,�����޸ĵ�����
	 * 
	 * @param sqlid
	 *            ��Ҫִ�е�sql��id,���id����namespace,��sqlmap�ļ�������
	 * @param parameter
	 *            sqlmap��ָ����sql���ܵĲ���,������ÿ�����String,javabean,����map
	 * @return Ӱ�������
	 */
	@Override
	public int updateBySqlID(String sqlID, Object parameter) {
		return getSqlMapClientTemplate().update(sqlID, parameter );
	}
	/**
	 * ִ���޸����͵�sql,�����޸ĵ�����
	 * 
	 * @param sqlid
	 *            ��Ҫִ�е�sql��id,���id����namespace,��sqlmap�ļ�������
	 * @param parameter
	 *            sqlmap��ָ����sql���ܵĲ���,������ÿ�����String,javabean,����map
	 * @return Ӱ�������
	 */
	@Override
	public int deleteBySqlID(String sqlID, Object parameter) {
		return getSqlMapClientTemplate().delete(sqlID, parameter );
	}
	/**
	 * ִ��insert���͵�sql,�����޸ĵ�����
	 * 
	 * @param sqlid
	 *            ��Ҫִ�е�sql��id,���id����namespace,��sqlmap�ļ�������
	 * @param parameter
	 *            sqlmap��ָ����sql���ܵĲ���,������ÿ�����String,javabean,����map
	 * @return
	 */

	@Override
	public Object insertBySqlID(String sqlID, Object parameter) {
		return getSqlMapClientTemplate().insert(sqlID, parameter );
	}
	/**
	 * @see com.dota.framework.dao.ibatis.GenericDAO#insert(com.dota.framework.domain.BaseBean)
	 */
	@Override
	public Long insert(BaseBean value) {
		return (Long) getSqlMapClientTemplate()
		.insert(
				super.getDaoNameSpace(value.getClass())
				+ POSTFIX_INSERT, value);
	}

	/**
	 * @see com.dota.framework.dao.GenericDao#insert(java.lang.Class, java.util.Map)
	 */
	@Override
	public Long insert(Class<? extends BaseBean> clazz, Map<String, Object> value) {
		return (Long) getSqlMapClientTemplate().insert(getDaoNameSpace(clazz)
				+POSTFIX_INSERT_BY_MAP, value);
	}

	/**
	 * @see com.dota.framework.dao.ibatis.GenericDAO#update(com.dota.framework.domain.BaseBean, java.lang.String[])
	 */
	@Override
	public int update(BaseBean value, String[] filter) {
		HashMap map = new HashMap();
		map.put("value", value);
		if (filter != null) {
			map.put("filter", filter);
		}
		return getSqlMapClientTemplate().update(
				super.getDaoNameSpace(value.getClass()) + POSTFIX_UPDATE, map);
	}

	/**
	 * @see com.dota.framework.dao.GenericDao#update(java.lang.Class, java.util.Map, java.lang.String[])
	 */
	@Override
	public int update(Class<? extends BaseBean> clazz, Map<String,?> value, String[] filter) {
		Map map = new HashMap(2);
		map.put("value", value);
		if (filter != null) {
			map.put("filter", filter);
		}
		return getSqlMapClientTemplate().update(super.getDaoNameSpace(clazz) + POSTFIX_UPDATE, map);
	}

	/**
	 * @see com.dota.framework.dao.ibatis.GenericDAO#updateExclusive(com.dota.framework.domain.BaseBean, java.lang.String[])
	 */
	@Override
	public int updateExclusive(BaseBean value, String[] filter) {
		HashMap map = new HashMap();
		map.put("value", value);
		if (filter != null) {
			filter = getProperty(value.getClass(), filter);
			if (filter != null) {
				map.put("filter", filter);
			}
		}
		return getSqlMapClientTemplate().update(
				super.getDaoNameSpace(value.getClass()) + POSTFIX_UPDATE, map);
	}

	/**
	 * @see com.dota.framework.dao.GenericDao#updateExclusive(java.lang.Class, java.util.Map, java.lang.String[])
	 */
	@Override
	public int updateExclusive(Class<? extends BaseBean> clazz, Map<String,?> value, String[] filter) {
		HashMap map = new HashMap(2);
		map.put("value", value);
		if (filter != null) {
			filter = getProperty(clazz, filter);
			if (filter != null) {
				map.put("filter", filter);
			}
		}
		return getSqlMapClientTemplate().update(
				super.getDaoNameSpace(clazz) + POSTFIX_UPDATE, map);
	}

	// /**
	// * �����зǿ�ֵ��Ϊ����������Ӧ��¼��������filter��ָ����������е�ֵ
	// *
	// * @param value
	// * �����ֵ�������
	// * @param filter
	// * ���µ��������飬Ϊ�ո�����������
	// * @param sample
	// * ������
	// * @return ���¼�¼��
	// */
	// public int updateBySample(BaseBean value, String[] filter, BaseBean
	// sample) {
	// Condition condition = createCondition(sample);
	// return updateByCondition(value, filter, condition);
	// }

	/**
	 * @see com.dota.framework.dao.ibatis.GenericDAO#updateByCondition(com.dota.framework.domain.BaseBean, java.lang.String[], com.dota.framework.dao.Condition)
	 */
	@Override
	public int updateByCondition(BaseBean value, String[] filter,
			Condition condition) {
		HashMap map = new HashMap();
		map.put("value", value);
		if (filter != null) {
			map.put("filter", filter);
		}
		if (condition != null) {
			map.put("condition", condition.expand());
		}
		return getSqlMapClientTemplate()
		.update(
				super.getDaoNameSpace(value.getClass())
				+ POSTFIX_UPDATE_Sample, map);
	}
	public  <T extends BaseBean> int updateExclusiveByCondition(T value, String[] filter,
			Condition condition){
		HashMap map = new HashMap();
		map.put("value", value);
		if (filter != null) {
			filter = getProperty(value.getClass(), filter);
			if (filter != null) {
				map.put("filter", filter);
			}
		}
		return getSqlMapClientTemplate().update(
				super.getDaoNameSpace(value.getClass()) + POSTFIX_UPDATE, map);
	}
	/**
	 * @see com.dota.framework.dao.ibatis.GenericDAO#removeById(java.lang.Class, java.lang.Long)
	 */
	@Override
	public int removeById(Class clazz, Long id) {
		return getSqlMapClientTemplate().delete(
				super.getDaoNameSpace(clazz) + POSTFIX_DELETE_ID, id);
	}

	// /**
	// * �����зǿ�ֵ��Ϊ����ɾ����Ӧ��¼
	// *
	// * @param sample
	// * ������
	// * @return ɾ���¼��
	// */
	// public int removeBySample(BaseBean sample) {
	// Condition condition = createCondition(sample);
	// return removeByCondition(sample.getClass(), condition);
	// }

	/**
	 * @see com.dota.framework.dao.ibatis.GenericDAO#removeByCondition(java.lang.Class, com.dota.framework.dao.Condition)
	 */
	@Override
	public int removeByCondition(Class clazz, Condition condition) {
		return getSqlMapClientTemplate().delete(
				super.getDaoNameSpace(clazz) + POSTFIX_DELETE_SAMPLE,
				createParameter(condition, null, null));
	}

	/**
	 * @see com.dota.framework.dao.ibatis.GenericDAO#getById(java.lang.Class, java.lang.Long)
	 */
	@Override
	public <T extends BaseBean> T getById(Class<T> clazz, Long id) {
		return (T) getSqlMapClientTemplate().queryForObject(
				super.getDaoNameSpace(clazz) + POSTFIX_SELECT_ID, id);
	}

	// /**
	// * �����зǿ�ֵ��Ϊ������ѯ����ͨ������������������
	// *
	// * @param clazz
	// * ���������
	// * @param sample
	// * ������
	// * @param orders
	// * ��������
	// * @return ������б�
	// */
	// public List getBySample(Class clazz, BaseBean sample, OrderPart orders) {
	// Condition condition = null;
	// if (sample != null) {
	// condition = createCondition(sample);
	// }
	// return getByCondition(clazz, condition, orders);
	// }

	/**
	 * @see com.dota.framework.dao.ibatis.GenericDAO#getByCondition(java.lang.Class, com.dota.framework.dao.Condition, com.dota.framework.dao.OrderPart)
	 */
	@Override
	public <T extends BaseBean> List<T> getByCondition(Class<T> clazz, Condition condition,
			OrderPart orders) {
		return getSqlMapClientTemplate().queryForList(
				super.getDaoNameSpace(clazz) + POSTFIX_SELECT_SAMPLE,
				createParameter(condition, orders, null));
	}

	// /**
	// * �����зǿ�ֵ��Ϊ������ѯ
	// *
	// * @param sample
	// * ������
	// * @return �����
	// */
	// public Object getObjectBySample(BaseBean sample) {
	// Condition condition = createCondition(sample);
	// return getObjectByCondition(sample.getClass(), condition);
	// }

	/**
	 * @see com.dota.framework.dao.ibatis.GenericDAO#getObjectByCondition(java.lang.Class, com.dota.framework.dao.Condition)
	 */
	@Override
	public <T extends BaseBean> T getObjectByCondition(Class<T> clazz, Condition condition) {
		return (T) getSqlMapClientTemplate().queryForObject(
				super.getDaoNameSpace(clazz) + POSTFIX_SELECT_SAMPLE,
				createParameter(condition, null, null));
	}

	// /**
	// * @param sample
	// * ��ѯ����
	// * @param pageNo
	// * ��0ҳ��ʼ
	// * @param pageSize
	// * @return
	// */
	// /**
	// * �����зǿ�ֵ��Ϊ�������з�ҳ��ѯ����ͨ������������������
	// *
	// * @param clazz
	// * ���������
	// * @param sample
	// * ������
	// * @param orders
	// * ��������
	// * @param pageNo
	// * ҳ��,��ʼҳ��Ϊ0
	// * @param pageSize
	// * ÿҳ��ʾ��¼��
	// * @return ������б�
	// */
	// public List getPagedBySample(Class clazz, BaseBean sample, OrderPart
	// orders, int pageNo, int pageSize) {
	// Condition condition = null;
	// if (sample != null) {
	// condition = createCondition(sample);
	// }
	// return getPagedByCondition(clazz, condition, orders, pageNo, pageSize);
	// }

	/**
	 * @see com.dota.framework.dao.ibatis.GenericDAO#getPagedByCondition(java.lang.Class, com.dota.framework.dao.Condition, com.dota.framework.dao.OrderPart, int, int)
	 */
	@Override
	public <T extends BaseBean> List<T> getPagedByCondition(Class<T> clazz, Condition condition,
			OrderPart orders, int pageNo, int pageSize) {
		int offset = pageNo * pageSize;
		Map pageBean = createParameter(condition, orders, new PageBean(
				offset, pageSize));
		return getSqlMapClientTemplate().queryForList(
				super.getDaoNameSpace(clazz) + POSTFIX_SELECT_PAGE_SAMPLE,
				pageBean);
	}

	// /**
	// * �����зǿ�ֵ��Ϊ����ͳ�Ƽ�¼��
	// *
	// * @param clazz
	// * ���������
	// * @param sample
	// * ������
	// * @return ��¼��
	// */
	// public long getCountBySample(Class clazz, BaseBean sample) {
	// Condition condition = null;
	// if (sample != null) {
	// condition = createCondition(sample);
	// }
	// return getCountByCondition(clazz, condition);
	// }

	/**
	 * @see com.dota.framework.dao.ibatis.GenericDAO#getCountByCondition(java.lang.Class, com.dota.framework.dao.Condition)
	 */
	@Override
	public long getCountByCondition(Class clazz, Condition condition) {
		Long count = (Long) getSqlMapClientTemplate().queryForObject(
				super.getDaoNameSpace(clazz) + POSTFIX_COUNT,
				createParameter(condition, null, null));
		if (count != null) {
			return count.longValue();
		}
		return 0;
	}

	/**
	 * �������ݸ�sqlmap�Ĳ���
	 * 
	 * @param condition
	 *            ��������
	 * @param orders
	 *            ��������
	 * @param page
	 *            ��ҳ��Ϣ
	 * @return ����
	 */
	private Map createParameter(Condition condition, OrderPart orders,
			PageBean page) {
		Map parameter = new HashMap();
		if (condition != null && !condition.isEmpty()) {
			parameter.put("condition", condition.expand());
		}
		if (orders != null) {
			parameter.put("order", orders.getItems());
		}
		if (page != null) {
			parameter.put("pageinfo", page);
		}
		return parameter;
	}

	/**
	 * ����ת���ɲ�ѯ����
	 * 
	 * @param bean
	 *            �������
	 * @return ��ѯ��������
	 */
	private Condition createCondition(Object bean) {
		Condition condition = new Condition();
		try {
			Map describe = PropertyUtils.describe(bean);
			for (Iterator iterator = describe.keySet().iterator(); iterator
			.hasNext();) {
				Object key = iterator.next();
				Object value = describe.get(key);
				if (!key.equals("class")) {
					if (value != null && value.toString().trim().length() > 0) {
						condition.add(key.toString(), value);
					}
				}
			}

		} catch (Exception e) {
			log.error("createCondition error", e);
		}
		return condition;
	}

	private String[] getProperty(Class clazz, String[] filter) {
		try {
			ArrayList list = new ArrayList();
			PropertyDescriptor[] properties = PropertyUtils
			.getPropertyDescriptors(clazz);
			String prop="";char ac[]=null;
			for (int i = 0; i < properties.length; i++) {
				boolean exist = false;
				ac=properties[i].getName().toCharArray();
				ac[0]=Character.toLowerCase(ac[0]);
				prop=new String(ac);
				for (int j = 0; j < filter.length; j++) {
					if (prop.equals(filter[j])) {
						exist = true;
						break;
					}
				}
				if (!exist && !prop.equals("class")) {
					list.add(prop);
				}
			}
			return (String[]) list.toArray(new String[] {});
		} catch (Exception e) {
			log.error("getProperty error", e);
		}
		return null;
	}

//	class PageBean {
//		private int firstRow;
//
//		private int lastRow;
//
//		public PageBean(int firstRow, int lastRow) {
//			this.firstRow = firstRow;
//			this.lastRow = lastRow;
//		}
//
//		public int getFirstRow() {
//			return this.firstRow;
//		}
//
//		public int getLastRow() {
//			return this.lastRow;
//		}
//	}
	
	class PageBean {
		private int offset;

		private int rows;

		public PageBean(int offset, int rows) {
			this.offset = offset;
			this.rows = rows;
		}

		public int getOffset() {
			return this.offset;
		}

		public int getRows() {
			return this.rows;
		}
		
	}
	@Override
	public int batchUpdate(final Class<? extends BaseBean>  clazz, final List<? extends BaseBean> objects, final String[] filter) {
		if (objects.size() == 0)
			return 0;
		return ((Integer) getSqlMapClientTemplate().execute(
				new SqlMapClientCallback() {
					public Object doInSqlMapClient(SqlMapExecutor executor)
							throws SQLException {
						int length = objects.size();
						executor.startBatch();
						HashMap map = new HashMap(2);
						for (int i = 0; i < length; i++) {
							map = new HashMap(2);
							map.put("value", objects.get(i));
							if (filter != null) {
								map.put("filter", filter);
							}
							executor.update(getDaoNameSpace(clazz)
									+ POSTFIX_UPDATE, map);
						}
						int result = executor.executeBatch();
						return new Integer(result);
					}
				})).intValue();
	}
	/**
	 * @see com.dota.framework.dao.GenericDao#batchInsert(java.util.List)
	 */
	@Override
	public int batchInsert(final List<? extends BaseBean> objects) {
		if (objects.size() == 0) {
			return 0;
		}
		final Class clazz = objects.get(0).getClass();
		return ((Integer) getSqlMapClientTemplate().execute(
				new SqlMapClientCallback() {
					@Override
					public Object doInSqlMapClient(SqlMapExecutor executor)
					throws SQLException {
						int length = objects.size();
						executor.startBatch();
						for (int i = 0; i < length; i++) {
							executor.insert(getDaoNameSpace(clazz)
									+ POSTFIX_INSERT, objects.get(i));
						}
						int result = executor.executeBatch();
						return length;
					}
				}));
	}

	/**
	 * @see com.dota.framework.dao.GenericDao#batchInsert(java.lang.Class, java.util.List)
	 */
	@Override
	public int batchInsert(final Class<? extends BaseBean> clazz, final List<Map<String,Object>> objects) {
		if (objects.size() == 0) {
			return 0;
		}
		return ((Integer) getSqlMapClientTemplate().execute(
				new SqlMapClientCallback() {
					@Override
					public Object doInSqlMapClient(SqlMapExecutor executor)
					throws SQLException {
						int length = objects.size();
						executor.startBatch();
						for (int i = 0; i < length; i++) {
							executor.insert(getDaoNameSpace(clazz)
									+ POSTFIX_INSERT, objects.get(i));
						}
						int result = executor.executeBatch();
						return length;
					}
				}));
	}

	/**
	 * @see com.dota.framework.dao.GenericDao#execute(org.springframework.orm.ibatis.SqlMapClientCallback)
	 */
	@Override
	public Object execute(SqlMapClientCallback callback) {
		return getSqlMapClientTemplate().execute(callback);
	}
	@Override
	public  int updateBySqlStr(String sql){
		return getSqlMapClientTemplate().update(FRAMEWORK_DAO_NAMESPACE + ".update",sql);
	}
	@Override
	public  int deleteBySqlStr(String sql){
		int ret=0;
		ret= getSqlMapClientTemplate().delete(FRAMEWORK_DAO_NAMESPACE + ".delete",sql);
		return ret;
	}
	//	public Long insertBySqlID(String sqlID,Map data) {
	//	  return (Long)getSqlMapClientTemplate().insert(sqlID,data);
	//
	//	}
	//
	//	public int updateBySqlID(String sqlID,Map data) {
	//		return getSqlMapClientTemplate().update(sqlID, data);
	//
	//	}

}
